import {randomMobileUserAgent, randomPCUserAgent, UserAgentKey} from "../common.js";
import {load} from 'cheerio';


/**
 * 请求参数类
 */
class RequestOptions {
    /**
     *
     * @param {RequestType} type 请求类型
     * @param {RequestMethod} method 请求方法，WebView只支持get、post
     * @param {Object.<string, string>} headers 请求头
     * @param {Boolean} ignoreUserAgent 是否忽略UserAgent，默认false，忽略不自动设置UserAgent
     * @param {String|null} proxy 代理，只在测试时有效（App只会使用系统代理，如：v2rayN），结构：protocol://username:password@proxyHost:proxyPort
     * @param {String|null} body 请求体
     * @param {String|null} decoder 响应数据解密的编码方式，如：utf-8、GBK，注意：如果type为webView，则会忽略本参数
     * @param {DeviceType} deviceType 设备类型，会根据这个值设置User-Agent的默认值
     * @param {Number} timeout 请求超时时间，单位 毫秒 ms ，默认 120 秒
     * @param {Number} retryCount 请求重试次数，默认为 3
     * @param {Number} delayedGetContent 延时获取内容，单位 毫秒 ms，默认：0。注意：只在WebView下生效，因为有的内容可能是js发送fetch然后再渲染的。
     * @param {RequestInputType} inputType 手动输入内容的类型，注意：只在WebView和开发测试阶段有效，可用在如起点等拦截人机的网站（会检测到自动化工具）
     */
    constructor({
                    type = RequestType.fetch,
                    method = RequestMethod.get,
                    headers = {},
                    ignoreUserAgent = false,
                    proxy = null,
                    body = null,
                    decoder = null,
                    deviceType = DeviceType.pc,
                    timeout = 120 * 1000,
                    retryCount = 3,
                    delayedGetContent = 0,
                    inputType = RequestInputType.none
                } = {}) {
        this.type = type;
        this.method = method;
        this.headers = headers;
        this.ignoreUserAgent = ignoreUserAgent;
        this.proxy = proxy;
        this.body = body;
        this.decoder = decoder;
        this.deviceType = deviceType;
        this.timeout = timeout;
        this.retryCount = Math.max(retryCount, 1);
        this.delayedGetContent = Math.max(delayedGetContent, 0);
        this.inputType = inputType;

        if (!this.ignoreUserAgent) {
            // 先判断是否设置了UA
            let noUserAgent = true;
            for (const header of Object.keys(this.headers)) {
                if (header.toLowerCase() === UserAgentKey.toLowerCase()) {
                    noUserAgent = false;
                    break;
                }
            }
            // 没有设置UA，则设置默认的UA
            if (noUserAgent) {
                if (this.deviceType.toLowerCase() === DeviceType.pc) {
                    headers[UserAgentKey] = randomPCUserAgent();
                } else {
                    headers[UserAgentKey] = randomMobileUserAgent();
                }
            }
        }
    }
}

const RequestType = {
    fetch: "fetch", webView: "webView"
}

const RequestMethod = {
    get: "get", post: "post", put: "put", delete: "delete"
}
const DeviceType = {
    pc: "pc", mobile: "mobile"
}
// 手动输入的类型
const RequestInputType = {
    none: 0,
    filePath: 1,
    cookies: 2,
    all: 3,
    /**
     *
     * @param inputType
     * @return {boolean}
     */
    isFilePath(inputType) {
        return inputType === this.filePath || inputType === this.all;
    },
    /**
     *
     * @param inputType
     * @return {boolean}
     */
    isCookies(inputType) {
        return inputType === this.cookies || inputType === this.all;
    }
}

/**
 * 请求响应类
 */
class RequestResponse {

    is2xx = 200 <= this.status && this.status < 300;

    is3xx = 300 <= this.status && this.status < 400;

    is4xx = 400 <= this.status && this.status < 500;

    is5xx = 500 <= this.status && this.status < 600;

    ok = this.is2xx;

    /**
     * 请求响应的数据
     * @param {String} url
     * @param {Number} status
     * @param {function():Promise<String>} text
     * @param {Object.<String,String>|null} headers 使用fetch发送请求的时候，会返回Response的headers
     * @param {function():Promise<String|null>} cookies 当使用WebView发送请求的时候，会返回当前网页的cookies字符串，格式参考 浏览器 -> 控制台-> NetWork -> Request Cookie
     */
    constructor({url, status = 200, text, headers = null, cookies = null} = {}) {
        this.url = url;
        this.status = status;
        this._text = text;
        this.headers = headers;
        this.cookies = cookies;
    }

    async text() {
        if (this._textStr === undefined) {
            this._textStr = await this._text();
        }
        return this._textStr;
    }

    async json() {
        return JSON.parse(await this.text());
    }

    /**
     *
     * @return {Promise<import('cheerio').CheerioAPI>}
     */
    async doc() {
        return load(await this.text())
    }

}

/**
 * 获取Cookies的可选参数
 */
class GetCookiesOptions {
    /**
     *
     * @param {Number} timeout 超时时间，单位毫秒
     */
    constructor({timeout = 120 * 1000,} = {}) {
        this.timeout = timeout;
    }
}

export {
    RequestOptions, RequestType, RequestMethod, DeviceType, RequestResponse, RequestInputType, GetCookiesOptions
}